package org.finesys.common.mq.dynamic;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.finesys.common.mq.properties.RabbitModuleProperties;
import org.springframework.amqp.core.AbstractExchange;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.HeadersExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RequiredArgsConstructor
@Slf4j
public class RabbitModuleInitializer implements SmartInitializingSingleton {
    private final AmqpAdmin amqpAdmin;
    private final RabbitModuleProperties rabbitModuleProperties;


    @Override
    public void afterSingletonsInstantiated() {
        log.info("RabbitMQ 根据配置动态创建和绑定队列、交换机");
        declareRabbitModule();
    }

    /**
     * RabbitMQ 根据配置动态创建和绑定队列、交换机
     */
    private void declareRabbitModule() {
        List<RabbitModuleInfo> moduleInfoList = rabbitModuleProperties.getModules();
        if (CollectionUtils.isEmpty(moduleInfoList)) {
            return;
        }
        moduleInfoList.stream().forEach(info -> {
            //验证参数
            configValidParam(info);
            // 队列
            Queue queue = convertQueue(info.getQueue());
            // 交换机
            Exchange exchange = convertExchange(info.getExchange());
            //
            String routingKey = info.getRoutingKey();
            String queueName = info.getQueue().getName();
            String exchangeName = info.getExchange().getName();
            Binding binding = new Binding(queueName, Binding.DestinationType.QUEUE, exchangeName, routingKey, null);
            //创建队列
            amqpAdmin.declareQueue(queue);
            amqpAdmin.declareExchange(exchange);
            amqpAdmin.declareBinding(binding);
        });

    }

    /**
     * 转换生成RabbitMQ队列
     *
     * @param queue 队列信息
     * @return 队列
     */
    private Queue convertQueue(RabbitModuleInfo.Queue queue) {
        Map<String, Object> arguments = queue.getArguments();
        if(arguments==null){
            arguments=new HashMap<>();
        }
        //转换ttl的类型为long
        if (arguments != null && arguments.containsKey("x-message-ttl")) {
            arguments.put("x-message-ttl", Long.valueOf(arguments.get("x-message-ttl").toString()));
        }
        //是否绑定死信队列
        String deadLetterExchange = queue.getDeadLetterExchange();
        String deadLetterRoutingKey = queue.getDeadLetterRoutingKey();
        if (StringUtils.hasText(deadLetterRoutingKey) && StringUtils.hasText(deadLetterExchange)) {
            arguments.put("x-dead-letter-exchange", deadLetterExchange);
            arguments.put("x-dead-letter-routingKey", deadLetterRoutingKey);
        }
//        String name, boolean durable, boolean exclusive, boolean autoDelete, @Nullable Map<String, Object> arguments
        return new Queue(queue.getName(), queue.isDurable(), queue.isExclusive(), queue.isAutoDelete(), arguments);
    }

    /**
     * 转换生成RabbitMQ交换机
     *
     * @param exchange 交换机信息
     * @return 交换机
     */
    private Exchange convertExchange(RabbitModuleInfo.Exchange exchange) {

        AbstractExchange abstractExchange = null;
        RabbitExchangeTypeEnum typeEnum = exchange.getType();
        String exchangeName = exchange.getName();
        boolean durable = exchange.isDurable();
        boolean autoDelete = exchange.isAutoDelete();

        Map<String, Object> arguments = exchange.getArguments();
        switch (typeEnum) {
            //直接交换机
            case DIRECT:
                abstractExchange = new DirectExchange(exchangeName, durable, autoDelete, arguments);
                //主题交换机
            case TOPIC:
                abstractExchange = new TopicExchange(exchangeName, durable, autoDelete, arguments);
                //扇形交换机
            case FANOUT:
                abstractExchange = new FanoutExchange(exchangeName, durable, autoDelete, arguments);
                //头交换机
            case HEADERS:
                abstractExchange = new HeadersExchange(exchangeName, durable, autoDelete, arguments);
            default:
                break;
        }
        return abstractExchange;
    }


    /**
     * RabbitMQ动态配置参数校验
     *
     * @param info 队列和交换机机绑定关系
     */
    private void configValidParam(RabbitModuleInfo info) {
        String routingKey = info.getRoutingKey();
        Assert.isTrue(routingKey != null, "RoutingKey未配置");
        Assert.isTrue(info.getExchange() != null, String.format("RoutingKey[%s]未配置Exchange", routingKey));
        Assert.isTrue(info.getExchange().getName() != null, String.format("RoutingKey[%s]未配置Exchange的名字[%s]", routingKey, info.getExchange().getName()));
        Assert.isTrue(info.getQueue() != null, String.format("RoutingKey[%s]未配置Queue", routingKey));
        Assert.isTrue(info.getQueue().getName() != null, String.format("RoutingKey[%s]未配置Queue的名字[%s]", routingKey, info.getQueue().getName()));
    }
}
